﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Enterprise.Data.Dynamic;
using Enterprise.Core;
using System.Reflection;
using Enterprise.Data;
using System.Linq.Expressions;
using Enterprise.Logging;
using System.Collections;
using System.Data.Linq;

namespace Viewer.BusinessObject.BusinessEntities
{
    public class BusinessBase1<TEntity> : Enterprise.Business.BusinessBase<TEntity> where TEntity :class
    {
        private DataClassesDataContext _context;
        public  DataClassesDataContext Context
        {
            get
            {
                if (_context == null) {
                    if (Enterprise.Core.CurrentContext.GetFromStorage("DataClassesDataContext") == null)
                    {
                        _context = new DataClassesDataContext();
                        Enterprise.Core.CurrentContext.PutIntoStorage("DataClassesDataContext", _context);
                    }
                    else
                    {
                        _context = (DataClassesDataContext)Enterprise.Core.CurrentContext.GetFromStorage("DataClassesDataContext");
                    }
                    
                }
                return _context;
            }
            set { 
                _context=value;
                Enterprise.Core.CurrentContext.PutIntoStorage("DataClassesDataContext", _context);
            }
        }
        
        public System.Data.Linq.Table<TEntity> CurrentTable
        {
            get 
            {
                return this.Context.GetTable<TEntity>(); 
            }
        }

        public override int Id
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        #region Copy
        public override void Copy(TEntity source, TEntity target)
        {
            this.Copy(source, target, false);
        }
        public override void Copy(TEntity source, TEntity target, bool detach)
        {
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }
            if (target == null)
            {
                throw new ArgumentNullException("target");
            }
            DataMapper.Map(source, target, true, new string[0]);
            if (detach)
            {
                if (this.Context != null)
                {
                    this.Context.Dispose();
                    this.Context = null;
                }
                this.Context = new DataClassesDataContext();
            }
        }
        #endregion

        #region Delete
        public override void Delete()
        {
            this.DeleteById(this.Id);
        }
       
        public virtual void DeleteById(Int32 id)
        {
            var entity = this.GetByID(id);
            this.CurrentTable.DeleteOnSubmit(entity);
        }

        public override void DeleteById(Int32 id, bool physicalDeletion)
        {
            TEntity entity = this.GetByID(id) as TEntity;
            if (entity == null)
            {
                return;
            }
            try
            {
                if (physicalDeletion)
                {
                    this.CurrentTable.DeleteOnSubmit(entity);
                }
                //entity.IsDeleted = "1";
                this.Update(entity);
            }
            catch (Exception exception)
            {
                Logger.Error(this, MethodBase.GetCurrentMethod().Name, exception.ToString());
                throw exception;
            }
        }

        public override void DeleteByQuery<TEntity>(Expression<Func<TEntity, bool>> wherePredicate)
        {
            TEntity entity = this.GetByID(1) as TEntity;
            if (entity == null)
            {
                return;
            }
            try
            {
               
            }
            catch (Exception exception)
            {
                Logger.Error(this, MethodBase.GetCurrentMethod().Name, exception.ToString());
                throw exception;
            }
        }

        //public override void DeleteByQuery<TEntity>(Expression<Func<TEntity, bool>> wherePredicate,  bool physicalDeletion) 
        //{
        //    IQueryable<TEntity> table = this.Context.GetTable();
        //    if (wherePredicate != null)
        //    {
        //        table = table.Where<TEntity>(wherePredicate);
        //    }
        //    DLinqPersistenceHelper.DeleteByQueryHelper(this.Context, table, physicalDeletion);
        //}

        #endregion

        #region Insert
        public override void Insert()
        {
            this.Insert(this as TEntity);
        }

        public override void Insert(TEntity entity)
        {
            try
            {
                this.CurrentTable.InsertOnSubmit(entity);
            }
            catch (Exception exception)
            {
                Logger.Error(this, MethodBase.GetCurrentMethod().Name, exception.ToString());
                throw exception;
            }
            
        }
        #endregion

        #region Update
        public override void Update()
        {
            var entityLinq = this.GetByID(this.Id);
            this.MapProperties(entityLinq);
        }

        public void Update(Int32 id)
        {
            var entityLinq = this.GetByID(id);
            this.MapProperties(entityLinq);
        }

        public override void Update(TEntity entity)
        {
            var entityLinq = this.GetByID(this.Id);
            this.MapProperties(entity, entityLinq);
        }
        #endregion

        #region Select
        public override IEnumerable Retrieve(int startRowIndex, int maximumRows, string sortExpression, string selector, string query, params object[] parameterValues)
        {
            IQueryable table = this.Context.GetTable<TEntity>();
            try
            {
                if (!string.IsNullOrEmpty(query))
                {
                    
                    table = table.Where(query, parameterValues);
                }
                //if (!includeDeleted)
                //{
                //    DLinqPersistenceManager<TEntity>.ExcludeDeleted(ref table);
                //}
                if (!string.IsNullOrEmpty(selector))
                {
                    table = table.Select(selector, new object[0]);
                }
                int num = table.Count();

                if (num > 1)
                {
                    if (string.IsNullOrEmpty(sortExpression))
                    {
                        table = table.Skip(startRowIndex);
                    }
                    else
                    {
                        table = table.OrderBy(sortExpression, new object[0]).Skip(startRowIndex);
                    }
                    if (maximumRows > 0)
                    {
                        table = table.Take(maximumRows);
                    }
                }
            }
            catch (Exception exception)
            {
                Logger.Error(this, MethodBase.GetCurrentMethod().Name, exception.ToString());
                throw;
            }
            return table;
        }

        public List<TEntity> Search(string query)
        {
            if (string.IsNullOrEmpty(query.Trim())) query = "1=1";
            return this.CurrentTable.Where(query).ToList();
        }

        public override TEntity GetByID(Int32 id)
        {
            throw new NotImplementedException();
        }

        public override List<TEntity> GetAll()
        {
            return this.Context.GetTable<TEntity>().ToList<TEntity>();
        }

        public IQueryable<TEntity> GetQuery(int startRowIndex, int maximumRows)
        {
            IQueryable<TEntity> table = this.Context.GetTable<TEntity>();
            return table.Skip<TEntity>(startRowIndex).Take<TEntity>(maximumRows);
        }


        #endregion

        #region Save Method
       

        public void SubmitChanges()
        {
            this.Context.SubmitChanges();
        }

        #endregion

        public virtual void MapProperties(TEntity entityLinq)
        {
            
        }

        private void MapProperties(TEntity entity, TEntity entityFromDB)
        {
            PropertyInfo[] properties = entityFromDB.GetType().GetProperties();
            foreach (PropertyInfo property in properties)
            {
                if (null != property.GetSetMethod())
                {
                    //Just one Line Of Code to Do the mapping
                    Enterprise.Base.MappingProvider.MapProperties(entity, entityFromDB, property);
                }
            }
        }

        #region Dispose
        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        private void Dispose(bool disposing)
        {
            if (disposing && (this.Context != null))
            {
                this.Context.Dispose();
                this.Context = null;
            }
        }
        #endregion

        public int ExecuteNativeCommand(string command, params object[] parameterValues)
        {
            int num;
            if (string.IsNullOrEmpty(command))
            {
                throw new ArgumentNullException("command");
            }
            try
            {
                num = this.Context.ExecuteCommand(command, parameterValues);
            }
            catch (Exception exception)
            {
                Logger.Error(this, MethodBase.GetCurrentMethod().Name, exception.ToString());
                throw;
            }
            return num;
        }

        public IEnumerable<TEntity> ExecuteNativeQuery(string query, params object[] parameterValues)
        {
            if (string.IsNullOrEmpty(query))
            {
                throw new ArgumentNullException("query");
            }
            IEnumerable<TEntity> enumerable = null;
            List<TEntity> list = new List<TEntity>();
            try
            {
                enumerable = this.Context.ExecuteQuery<TEntity>(query, parameterValues);
            }
            catch (Exception exception)
            {
                Logger.Error(this, MethodBase.GetCurrentMethod().Name, exception.ToString());
                throw;
            }
            foreach (TEntity local in enumerable)
            {
                list.Add(local);
            }
            return list;
        }

        public IEnumerable<TResult> ExecuteNativeQuery<TResult>(string query, params object[] parameterValues)
        {
            if (string.IsNullOrEmpty(query))
            {
                throw new ArgumentNullException("query");
            }
            IEnumerable<TResult> enumerable = null;
            List<TResult> list = new List<TResult>();
            try
            {
                enumerable = this.Context.ExecuteQuery<TResult>(query, parameterValues);
            }
            catch (Exception exception)
            {
                Logger.Error(this, MethodBase.GetCurrentMethod().Name, exception.ToString());
                throw;
            }
            foreach (TResult local in enumerable)
            {
                list.Add(local);
            }
            return list;
        }

        #region Undeleted
        //public void Undeleted()
        //{
        //    this.Undelete(this as TEntity);
        //}

        //public override void Undelete<TEntity>(TEntity entity)
        //{
        //    if (entity == null)
        //    {
        //        return;
        //    }
        //    //if (entity.IsDeleted == "0")
        //    //{
        //    //    return false;
        //    //}
        //    try
        //    {
        //        // entity.IsDeleted = "0";
        //        this.Update(this.Id);
        //    }
        //    catch (Exception exception)
        //    {
        //        Logger.Error(this, MethodBase.GetCurrentMethod().Name, exception.ToString());
        //        throw;
        //    }
            
        //}
        

        #endregion


        public virtual void Save()
        {
            if (this.Id == 0)
            {
                this.Insert(this as TEntity);
            }
            //else
            //{
            //    var entityLinq  = this.GetByID(this.Id);
                
            //    SetUpdateValue(ref entityLinq);
            //}
            this.SubmitChanges();
        }

        public virtual void SetUpdateValue(ref TEntity entity)  
        {
            
        }

        public override bool Exists<TEntity>(Expression<Func<TEntity, bool>> wherePredicate, bool includeDeleted)
        {
            throw new NotImplementedException();
        }

        public override int GetCount<TEntity>(Expression<Func<TEntity, bool>> wherePredicate, bool includeDeleted)
        {
            throw new NotImplementedException();
        }
    }
}